/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

package ru.teleology.cubefs.editor.model;

import java.util.ArrayList;
import java.util.List;

import ru.teleology.cubefs.api.models.Page;
import ru.teleology.cubefs.api.reflection.Typed;
import ru.teleology.cubefs.api.reflection.number.Number;
import ru.teleology.cubefs.api.reflection.metadata.FieldMetadata;
import ru.teleology.cubefs.api.reflection.metadata.FlagField;
import ru.teleology.cubefs.api.reflection.metadata.IDField;
import ru.teleology.cubefs.api.reflection.metadata.Metadata;
import ru.teleology.cubefs.api.reflection.metadata.MetadataGroup;
import ru.teleology.cubefs.api.reflection.metadata.NumberField;
import ru.teleology.cubefs.api.reflection.metadata.PageMetadata;
import ru.teleology.cubefs.api.reflection.value.TypedIDValue;

public class TreePageMetadataHelper {
	private final PageMetadata page;
	
	private IDField parentIDFiled;
	private NumberField childrenCountField;

	private NumberField modelNameField;
	
	private FlagField leafField;
	private FlagField rootField;
	
	private final List<NumberField> keyFields = new ArrayList<NumberField>();
	private final List<FieldMetadata> valueFields = new ArrayList<FieldMetadata>();
	
	private int keyCount;
	
	private boolean idValue; 
	
	public TreePageMetadataHelper(PageMetadata page) {
		this.page = page;
		
		parentIDFiled = (IDField) page.findField("PARENT_ID");
		
		rootField = (FlagField) page.findField("ROOT");
		leafField = (FlagField) page.findField("LEAF");
		
		modelNameField = (NumberField) page.findField("MODEL_NAME");
		
		MetadataGroup map = (MetadataGroup) page.findField("MAP");
		
		
		childrenCountField = (NumberField) map.findField("SIZE");

		for (int c = 0; c < map.Size(); c++) {
			Metadata field = map.GetItem(c);
			if ("ITEM".equals(field.Name())) {
				MetadataGroup item = (MetadataGroup) field;

				NumberField keys = (NumberField) item.findField("KEYS");
				keyCount = (int) keys.Size();

				keyFields.add(keys);

				FieldMetadata data = (FieldMetadata) item.findField("DATA");

				idValue = data instanceof IDField;

				valueFields.add(data);
			}
		}

	}
	
	public PageMetadata getPage() {
		return page;
	}
	
	public TypedIDValue getID(Page page) {
		return page.GetId();
	}
	
	public Number getModelName(Page page) {
		Number num = (Number) modelNameField.CreateValueHolder();
		modelNameField.GetValue(page, num);
		return num;
	}
	
	public TypedIDValue getParentID(Page page) {
		TypedIDValue id = (TypedIDValue) parentIDFiled.CreateValueHolder(); 
		parentIDFiled.GetValue(page, 0, id, false);
		return id;
	}
	
	public int getChildrenCount(Page page) {
		return (int) childrenCountField.GetValue(page, 0, false);
	}
	
	public int getKeyCount() {
		return keyCount;
	}
	
	public long getKey(Page page, int key, int idx) {
		return keyFields.get(idx).GetValue(page, key, false);
	}
	
	public Typed getData(Page page, int key, int idx) {
		FieldMetadata field = valueFields.get(idx);
		
		Typed value = field.CreateValueHolder();
		
		if (idValue) {
			((IDField)field).GetValue(page, key, (TypedIDValue)value, false);
		}
		else {
			((NumberField)field).GetValue(page, key, (Number)value, false);
		}
		
		return value;
	}
	
	public void getData(Page page, int idx, Typed value) {
		FieldMetadata field = valueFields.get(idx);
		if (idValue) {
			((IDField)field).GetValue(page, idx, (TypedIDValue)value, false);
		}
		else {
			((NumberField)field).GetValue(page, idx, (Number)value, false);
		}
	}
	
	public Typed getDataValue(Page page, int idx) {
		FieldMetadata field = valueFields.get(idx);
		
		Typed value = field.CreateValueHolder();
		
		if (idValue) {
			((IDField)field).GetValue(page, 0, (TypedIDValue)value, false);
		}
		else {
			((NumberField)field).GetValue(page, 0, (Number)value, false);
		}
		
		return value;
	}
	
	public boolean isLeaf(Page page) {
		return leafField.GetBits(page, 0, 1, false) == 1;
	}
	
	public boolean isRoot(Page page) {
		return rootField.GetBits(page, 0, 1, false) == 1;
	}

	public List<NumberField> getKeyFields() {
		return keyFields;
	}

	public List<FieldMetadata> getValueFields() {
		return valueFields;
	}
}
